import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, TreeRepository } from 'typeorm';
import { UuidResDto } from '../../common/dtos/uuid.res.dto';
import { OrganizationEntity } from '../entities/organization.entity';

@Injectable()
export class OrganizationService {
  constructor(
    @InjectRepository(OrganizationEntity)
    private readonly organizationRepository: TreeRepository<OrganizationEntity>
  ) {}

  /**
   * 创建组织
   * @param name 组织名称
   * @param level 组织等级
   * @param description 组织描述
   * @param parent 上级组织
   */
  async create(name: string, level: number, description?: string, parent?: OrganizationEntity): Promise<OrganizationEntity> {
    const organization = new OrganizationEntity();
    organization.name = name;
    organization.level = level;
    if (description) organization.description = description;
    if (parent) organization.parent = parent;

    return this.organizationRepository.save(organization);
  }

  /**
   * 通过编号删除组织
   * @param id 组织编号
   */
  async deleteOneById(id: number): Promise<DeleteResult> {
    return this.organizationRepository.delete(id);
  }

  /**
   * 组织名称
   * @param name 名称
   */
  async deleteAllByName(name: string): Promise<DeleteResult> {
    return this.organizationRepository
      .createQueryBuilder('organizations')
      .delete()
      .where('organizations.name LIKE :name', { name: `%${name}%` })
      .execute();
  }

  /**
   * 更新组织
   * @param id 编号
   * @param name 组织名称
   * @param description 组织描述
   */
  async update(id: number, name?: string, description?: string): Promise<OrganizationEntity> {
    const organization = await this.organizationRepository.findOne(id);
    if (name) organization.name = name;
    organization.description = description;

    return this.organizationRepository.save(organization);
  }

  /**
   * 通过编号获取组织
   * @param id 组织编号
   */
  async findOneById(id: number): Promise<OrganizationEntity> {
    return this.organizationRepository.findOne({ id: id });
  }

  /**
   * 通过名称获取组织
   * @param name 组织名称
   */
  async findOneByName(name: string): Promise<OrganizationEntity> {
    return this.organizationRepository.findOne({ name });
  }

  /**
   * 通过编号列表获取组织列表
   * @param idList 编号列表
   */
  async findByIdList(idList: number[]): Promise<OrganizationEntity[]> {
    return this.organizationRepository.createQueryBuilder('organizations').where('id = ANY(:idList)', { idList: idList }).getMany();
  }

  /**
   * 获取组织根节点
   */
  async findOneRoot(): Promise<OrganizationEntity> {
    const roots = await this.organizationRepository.findRoots();
    //There must be only one root
    return roots[0];
  }

  /**
   * 获取组织下的所有子组织列表
   * @param parent 上级组织
   */
  async findChildren(parent: OrganizationEntity): Promise<OrganizationEntity[]> {
    return this.organizationRepository.find({ parent: parent });
  }

  /**
   * 递归获取用户当前岗位下的所有岗位/组织id列表
   * @param id 用户当前岗位id
   */
  async findByRecursive(id: number): Promise<string[]> {
    const uuidList: UuidResDto[] = await this.organizationRepository.query(
      `WITH RECURSIVE cte AS (SELECT o.id FROM organizations o WHERE id = '${id}' UNION ALL SELECT k.id FROM organizations k INNER JOIN cte c ON c.id = k.parent_id) SELECT id FROM cte`
    );
    if (uuidList)
      return uuidList.map(recursive => {
        return recursive.uuid;
      });
    return [];
  }

  /**
   * 返回组织下所有节点数
   * @param parent 上级组织
   */
  async findCount(parent: OrganizationEntity): Promise<number> {
    if (parent == null) return 0;

    return this.organizationRepository.countDescendants(parent);
  }

  /**
   * 通过名称获取组织所有直接子类别（没有其嵌套类别）
   * @param name 组织名称
   * @param parent 上级组织
   */
  async findDescendantsByName(name: string, parent?: OrganizationEntity): Promise<OrganizationEntity[]> {
    if (parent == null) {
      const roots = await this.organizationRepository.findRoots();
      if (roots && roots.length > 0) parent = roots[0];
    }
    if (parent == null) return null;

    // 返回parentCategory的所有直接子类别（没有其嵌套类别）
    const childrens = await this.organizationRepository.findDescendants(parent);

    return childrens.filter(child => child.name == name);
  }

  /**
   * 获取组织所有直接子类别（没有其嵌套类别）
   * @param parent 上级组织
   */
  async findDescendantsById(id: number): Promise<number[]> {
    const parent = await this.organizationRepository.findOne(id);
    // 返回parentCategory的所有直接子类别（没有其嵌套类别）
    const children = await this.organizationRepository.findDescendants(parent);

    return children.map(child => child.id);
  }

  /**
   * 返回parent的所有直接子组织（及其嵌套类别）
   * @param parent 上级组织
   */
  async findDescendantsTree(parent?: OrganizationEntity): Promise<OrganizationEntity> {
    if (parent == null) {
      const roots = await this.organizationRepository.findRoots();
      //There must be only one root
      parent = roots[0];
    }

    return this.organizationRepository.findDescendantsTree(parent);
  }
}
